/* $Header: p_conv.c,v 2.2 01/10/02 10:27:47 przybyls Exp $ */

/***********************************************************************/
/*                                                                     */
/*                  Copyright Hewlett-Packard Co. 1991                 */
/*                                                                     */
/***********************************************************************/

/***********************************************************************/
/* MODULE NAME:  adc_conv.c                                            */
/* ============                                                        */
/*                                                                     */
/* Author: wikfors                                                     */
/*                                                                     */
/* MODULE PURPOSE: handle conversion of adc <-> flow/pres values and   */
/*                 perform any calibration needed on the converted     */
/*                 values.                                             */
/*                                                                     */
/*                 these functions apply to INLETS ONLY !              */
/*                                                                     */
/***********************************************************************/


/*****************************/
/*   GLOBAL INCLUDE FILES    */
/*****************************/


#include <typedefs.h>
#include <error.h>
#include <p_wkfile.h>
#include <i_op.h>
#include <p_status.h>
#include <m68332.h>
#include <math.h>
#include <list_mgmt.h>
#include <pcb_defs.h>
#include <keyboard.h>
#include <ramps.h>
#include <wkfile.h>
#include <zone_config.h>
#include <zone_status.h>
#include <status.h>

/*****************************/
/*   LOCAL INCLUDE FILES     */
/*****************************/

#include "proto.h"
#include "p_tcomp.h"

/*****************************/
/*   GLOBAL VARIABLES        */
/*****************************/


/*****************************/
/*   EXTERNAL VARIABLES      */
/*****************************/


/*****************************/
/*   LOCAL DEFINES           */
/*****************************/


/*****************************/
/*   STATIC VARIABLES        */
/*****************************/


/*****************************/
/*   IMPLEMENT SECTION       */
/*****************************/
/**begin_proto**/

#pragma SECTION PROG=rom3

/**end_proto**/

/***********************************************************************/
/* FUNCTION:                                                           */
/* ========                                                            */
/*                                                                     */
/* PURPOSE:                                                            */
/*                                                                     */
/* RETURNED VALUE:                                                     */
/*                                                                     */
/* GLOBALS USED:                                                       */
/*                                                                     */
/***********************************************************************/

#define OFFSET_REMAINDER 8

#define OFFSET_DELAY     3

/**begin_proto**/

void JamOffsetFilter ( U_INT32 *filter, U_INT16 value )

/**end_proto**/
{

     *filter = value << OFFSET_REMAINDER;

}

/**begin_proto**/

void OffsetFilter ( U_INT32 *filter, U_INT16 value )

/**end_proto**/
{

     U_INT32 scratch;
     U_INT32 delta;

     scratch = value << OFFSET_REMAINDER;

     if ( *filter > scratch )
     {
         /* the filter is greater than the new value */

         delta = ( *filter - scratch ) >> OFFSET_DELAY;

         if ( delta != 0 ) *filter -= delta;
         else              *filter -= 1;
     }
     else if ( scratch > *filter )
     {
         /* the filter is smaller than the new value */

         delta = ( scratch - *filter ) >> OFFSET_DELAY;

         if ( delta != 0 ) *filter += delta;
         else              *filter += 1;
     }
}


/**begin_proto**/

INT16 GetFilteredOffset ( U_INT32 *filter )

/**end_proto**/
{

     return  *filter >> OFFSET_REMAINDER;

}

/**begin_proto**/

U_INT16 SubtractAdcOffset( U_INT16 volts )

/**end_proto**/
{
     U_INT16 offset;

     INTERRUPTS_OFF

     offset = Inst_Status.Pneu.Environment.ADC_Offset;

#ifndef mccabe
#pragma ASM

     clr.l   d0                    ; make volts 32bits signed
     move.w  (S_volts,A6),d0          ; load as unsigned (since it is always positive)

     ext.l   d2                    ; make offset 32 bits signed

     sub.l   d2,d0                 ; sub offset from volts

     bpl.b   SAO_Not_Negative
     clr.l   d0                    ; force negative results to zero

SAO_Not_Negative
     move.l  #$ffff,d2
     cmp.l   d2,d0                 ; did we overflow?
     bmi.b   SAO_Done

     move.w  d2,d0

SAO_Done

     move.w  d0,(S_volts,A6)

#pragma END_ASM
#else
volts = volts - offset;
#endif

     INTERRUPTS_ON

//     (void) offset;

     return volts;

}


/**begin_proto**/

U_INT16 AddAdcOffset( U_INT16 volts )

/**end_proto**/
{
     U_INT16 offset;

     offset = Inst_Status.Pneu.Environment.ADC_Offset;

#ifndef mccabe
#pragma ASM

     clr.l   d0                    ; make volts 32bits signed
     move.w  (S_volts,A6),d0          ; load as unsigned (since it is always positive)

     ext.l   d2                    ; make offset 32 bits signed

     add.l   d2,d0                 ; add offset to volts

     bpl.b   AAO_Not_Negative
     clr.l   d0                    ; force negative results to zero

AAO_Not_Negative
     move.l  #$ffff,d2
     cmp.l   d2,d0                 ; did we overflow?
     bmi.b   AAO_Done

     move.w  d2,d0

AAO_Done

     move.w  d0,(S_volts,A6)

#pragma END_ASM
#else
volts = volts + offset;
#endif

     (void) offset;

     return volts;

}

/***********************************************************************/
/* FUNCTION:  PresToVolts                                              */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: convert an internal unit pressure reading to a pressure    */
/*          sensor voltage reading.                                    */
/*                                                                     */
/* RETURNED VALUE: a presure sensor voltage setpoint                   */
/*                                                                     */
/***********************************************************************/


/**begin_proto**/

U_INT16 PresToVolts ( U_INT16 pressure, pPRES_SENSOR_STRUCT sensor, U_INT16 module_temp, INT16 calib_offset, U_INT16 calib_gain )

/**end_proto**/
{

    U_INT16 volts;
    INT32   delta_T;
    U_INT16 span;
    U_INT16 offset;

     delta_T = ( module_temp - (U_INT16)TCOMP_STD_TEMP_IU );

     if ( sensor->Temp_Comp_Enabled == TRUE )
     {
         offset = sensor->Parms.Offset + delta_T * sensor->Parms.dOffset_dT / PS_dT_SCALING;
         span   = sensor->Parms.Span   + delta_T * sensor->Parms.dSpan_dT   / PS_dT_SCALING;
     }
     else
     {
         offset = sensor->Parms.Offset;
         span   = sensor->Parms.Span;
     }

     offset = offset + calib_offset;
     span   = QuadWordMultiplyDivide( span, calib_gain, CALIB_GAIN_SCALING );

     volts = ((  (U_INT32)pressure * span ) / sensor->Parms.Range ) + offset;

     sensor->Pres_Setpt       = pressure;
     sensor->Pres_Volts_Setpt = volts;
     sensor->Pres_Adc_Setpt   = volts;
     sensor->Pres_dV_Setpt    = volts -
        ((((U_INT32)pressure * sensor->Parms.Span ) / sensor->Parms.Range ) * CALIB_GAIN_SCALING ) / calib_gain
         - sensor->Parms.Offset - calib_offset;

     if ( pressure == 0 )
     {
         sensor->Pres_Setpt       = 0;
         sensor->Pres_Volts_Setpt = 0;
         sensor->Pres_Adc_Setpt   = 0;
         sensor->Pres_dV_Setpt    = 0;
         /* volts = 0; !! removed 10/16/95 for PRES=0 fix; must keep "offset" from above. sok  */
     }

     return  AddAdcOffset( volts );

}

/***********************************************************************/
/* FUNCTION:  VoltsToPres                                              */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: convert an sensor voltage reading to an internal unit      */
/*          pressure value                                             */
/*                                                                     */
/* RETURNED VALUE: pressure (guage) in iu                              */
/*                                                                     */
/***********************************************************************/
/**begin_proto**/

U_INT16 VoltsToPres ( U_INT16 volts, pPRES_SENSOR_STRUCT sensor, U_INT16 module_temp, INT16 calib_offset, U_INT16 calib_gain )

/**end_proto**/
{


    U_INT16 pressure;
    INT32   delta_T;
    U_INT16 span;
    U_INT16 offset;



      /* protect against uninitialized values causing divide-by-zero */
      if (( sensor->Parms.Span == 0 ) || ( sensor->Parms.Range == 0 ))
      {
         return 0;
      }

      /* remove the adc offset and check for underflow */
      volts = SubtractAdcOffset( volts );

     delta_T = ( module_temp - (U_INT16)TCOMP_STD_TEMP_IU );

     if ( sensor->Temp_Comp_Enabled == TRUE )
     {
         offset = sensor->Parms.Offset + delta_T * sensor->Parms.dOffset_dT / PS_dT_SCALING;
         span   = sensor->Parms.Span   + delta_T * sensor->Parms.dSpan_dT   / PS_dT_SCALING;
     }
     else
     {
         offset = sensor->Parms.Offset;
         span   = sensor->Parms.Span;
     }

     offset = offset + calib_offset;
     span   = QuadWordMultiplyDivide( span, calib_gain, CALIB_GAIN_SCALING );
/*
if(&Inst_Status.Pneu.Aux.Tcomp_Tables->Aux_3 == sensor)
{
printf("volts=%d,offset=%d,sensor->Parms.Offset=%d\n",volts,offset,sensor->Parms.Offset);
}*/
     if ( volts < offset )
     {
//printf("volts=%d,offset=%d,calib_offset=%d,calib_gain=%d\n",volts,offset,calib_offset,calib_gain);
        pressure = 0;
     }
     else
     {
        pressure = ( (U_INT32)volts - offset ) * sensor->Parms.Range / span;
//printf("pressure=%d\n",pressure);
     }


     sensor->Pres_Adc_Actual   = volts;
     sensor->Pres_Volts_Actual = volts + sensor->Pres_dV_Actual;
     sensor->Pres_Actual       = pressure;
     sensor->Pres_dV_Actual    =
        ((  (U_INT32)pressure * sensor->Parms.Span ) / sensor->Parms.Range ) * CALIB_GAIN_SCALING / calib_gain
              + calib_offset + sensor->Parms.Offset - volts;

     return pressure;
}

/***********************************************************************/
/* FUNCTION:  InletFsToVolts                                           */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: convert an internal unit flow reading to a flow sensor     */
/*          voltage reading.                                           */
/*                                                                     */
/* RETURNED VALUE: a flow sensor voltage setpoint                      */
/*                                                                     */
/***********************************************************************/
/**begin_proto**/

U_INT16 FlowToVolts ( U_INT32 flow, pFLOW_SENSOR_STRUCT sensor, U_INT16 module_temperature, INT16 calib_offset, U_INT16 calib_gain )

/**end_proto**/
{

      U_INT16 table_index;
      U_INT16 volts;
      INT16   dVolts;
      U_INT16 setpt;
      U_INT16 offset;
      INT16   delta_T;

      delta_T = (INT16) ( module_temperature - sensor->Parms.Reference_Temp );
      offset = sensor->Parms.Offset + (sensor->Parms.delta_offset_delta_t * delta_T) ;

      table_index = (flow & sensor->Mask) >> sensor->Shift_Value;
      volts = tableU( (U_INT16 *) sensor->Flow_To_Volts, table_index );

      if ( sensor->Temp_Comp_Enabled == TRUE )
      {
           dVolts = tableS( (INT16 *) sensor->dV_dT, ( volts >> sensor->Comp_Shift) );
           /* temp iu is 64'ths degree K, and we have a 64 scaling factor also */

           dVolts = (INT16) ( ((INT32)dVolts * delta_T) / (64*64) );
      }
      else
      {
          dVolts = 0;
      }


      setpt = volts + dVolts;

      if ( dVolts >= 0 )
      {
          if ( setpt < volts ) setpt = 0xffff; /* overflow */
      }
      else
      {
          if ( volts < setpt  ) setpt = 0; /* underflow */
      }

      setpt = QuadWordMultiplyDivide( setpt, calib_gain, CALIB_GAIN_SCALING );

      volts = volts + offset + calib_offset;
      setpt = setpt + offset + calib_offset;


      sensor->Flow_Setpt        = flow;
      sensor->Volts_Setpt       = volts;
      sensor->dV_Setpt          = dVolts;
      sensor->Total_Volts_Setpt = setpt;


      /* add adc offset and check for overflow */
      setpt = AddAdcOffset( setpt );


     if ( flow == 0 )
     {
         sensor->Flow_Setpt        = 0;
         sensor->Volts_Setpt       = 0;
         sensor->Total_Volts_Setpt = 0;
         sensor->dV_Setpt          = 0;
         setpt                     = 0;
     }
     return setpt;

}

/***********************************************************************/
/* FUNCTION:  InletVoltsToFlow                                         */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: convert a sensor voltage reading to a flow value in iu     */
/*                                                                     */
/* RETURNED VALUE:  a  flow value in iu                                */
/*                                                                     */
/***********************************************************************/


/**begin_proto**/

U_INT32 VoltsToFlow ( U_INT16 volts, pFLOW_SENSOR_STRUCT sensor, U_INT16 module_temperature, INT16 calib_offset, U_INT16 calib_gain )

/**end_proto**/
{
      U_INT16 actual;
      INT16   dVolts;
      U_INT32 flow;
      U_INT16 delta_t;
      U_INT16 offset;
      U_INT16 raw_volts;

      /* remove the adc offset and check for underflow */
      volts = SubtractAdcOffset( volts );
      raw_volts = volts;

      delta_t =  sensor->Parms.Reference_Temp - module_temperature;

      if ( sensor->Temp_Comp_Enabled == TRUE )
      {
          offset = sensor->Parms.Offset + calib_offset
                   + (INT32)delta_t * sensor->Parms.delta_offset_delta_t/FS_DOFFSET_SCALING;
      }
      else
      {
          offset = sensor->Parms.Offset + calib_offset ;
      }

      if ( volts > offset )
      {
          volts = QuadWordMultiplyDivide( (volts - offset), CALIB_GAIN_SCALING, calib_gain ) ;
      }
      else
      {
          volts = 0;
      }

      if ( sensor->Temp_Comp_Enabled == TRUE )
      {
           dVolts = tableS( (INT16 *) sensor->dV_dT, ( volts >> sensor->Comp_Shift ) );
           /* temp iu is 64'ths degree K, and we have a 64 scaling factor also */
           dVolts = (INT16)( ( (INT32)dVolts * (INT32) delta_t  ) / (64*64) );

           actual = volts + dVolts;

           if ( dVolts >= 0 )
           {
                if ( actual < volts ) actual = 0xffff; /* overflow */
           }
           else
           {
                if ( actual > volts ) actual = 0;      /* underflow */
           }

           dVolts = tableS( (INT16 *) sensor->dV_dT, ( actual >> sensor->Comp_Shift )) ;
           /* temp iu is 64'ths degree K, and we have a 64 scaling factor also */
           dVolts = (INT16)( ( (INT32)dVolts * (INT32)delta_t ) / (64*64) );

           actual = volts + dVolts;

           if ( dVolts >= 0 )
           {
              if ( actual < volts ) actual = 0xffff; /* overflow */
           }
           else
           {
              if ( actual > volts ) actual = 0;      /* underflow */
           }


           dVolts = tableS( (INT16 *) sensor->dV_dT, ( actual >> sensor->Comp_Shift )) ;
           /* temp iu is 64'ths degree K, and we have a 64 scaling factor also */
           dVolts = (INT16)( ( (INT32)dVolts * (INT32)( sensor->Parms.Reference_Temp - module_temperature ) ) / (64*64) );

           actual = volts + dVolts;

           if ( dVolts >= 0 )
           {
                if ( actual < volts ) actual = 0xffff; /* overflow */
           }
           else
           {
                if ( actual > volts ) actual = 0;      /* underflow */
           }

      }
      else
      {
           dVolts = 0;
           actual = volts + dVolts;
      }

      if ( actual <= 0 )

      {
          flow = 0;
      }
      else
      {
          flow = tableU( (U_INT32 *) sensor->Volts_To_Flow, actual );
      }


      sensor->Total_Volts_Actual = raw_volts;
      sensor->dV_Actual          = dVolts + (INT32)delta_t * sensor->Parms.delta_offset_delta_t/FS_DOFFSET_SCALING;
      sensor->Volts_Actual       = actual + offset;
      sensor->Flow_Actual        = flow;

      return flow;

}


/**begin_proto**/

U_INT16 FritFlowToPres ( U_INT32 desired_flow, pFRIT_STRUCT frit, U_INT16 module_temperature, U_INT16 atm_pres )

/**end_proto**/
{

     U_INT16 table_index;
     INT32   temp_factor;
     INT32   pres_factor;
     U_INT16 uncorrected_pres;
     U_INT16 pres;


        table_index = ( desired_flow &  frit->Mask ) >> frit->Shift_Value;

        uncorrected_pres = tableU((U_INT16 *)frit->Flow_To_Pres, table_index );

        if ( frit->Temp_Comp_Enabled == TRUE )
        {
             temp_factor = tableS((INT32 *)frit->Setpt_Temp_Correct_Per_T_IU, ( uncorrected_pres >> 3 ) );
             temp_factor = temp_factor * (module_temperature - (U_INT16)DET_TCOMP_STD_TEMP_IU) / CORRECT_SCALE;

             pres_factor = tableS((INT32 *)frit->Setpt_Pres_Correct_Per_P_IU, ( uncorrected_pres >> 3 ) );
             pres_factor = pres_factor * (atm_pres- (U_INT16)DET_TCOMP_STD_PRES_IU) / CORRECT_SCALE
                            + ( (U_INT16)DET_TCOMP_STD_PRES_IU - atm_pres );


             pres = uncorrected_pres + pres_factor + temp_factor;

             if ( (pres_factor + temp_factor) >= 0 )
             {
                 if ( pres < uncorrected_pres )  pres = 0xffff; /* overflow */
             }
             else
             {
                  if ( uncorrected_pres < pres  ) pres = 0; /* underflow */
             }

        }
        else
        {
             pres = uncorrected_pres;
             temp_factor = 0;
             pres_factor = 0;
        }


        frit->TCorr_Setpt = temp_factor;
        frit->PCorr_Setpt = pres_factor;
        frit->Pres_Setpt  = pres;
        frit->UPres_Setpt = uncorrected_pres;

        return pres;
}

/**begin_proto**/

U_INT32  FritPresToFlow ( U_INT16 pres, pFRIT_STRUCT frit, U_INT16 module_temperature, U_INT16 atm_pres )

/**end_proto**/
{


     INT32   temp_factor;
     INT32   pres_factor;
     U_INT16 uncorrected_pres;
     U_INT32 flow;


     if ( pres != 0 )
     {

          if ( frit->Temp_Comp_Enabled == TRUE )
          {

               pres_factor = tableS((INT32 *)frit->Setpt_Pres_Correct_Per_P_IU, ( pres >> 3 ) );

               pres_factor = pres_factor * ((U_INT16)DET_TCOMP_STD_PRES_IU - Atmospheric_Pressure.Dcm2_160) / CORRECT_SCALE
                               - ( (U_INT16)DET_TCOMP_STD_PRES_IU - Atmospheric_Pressure.Dcm2_160 );

               temp_factor = tableS((INT32 *)frit->Setpt_Temp_Correct_Per_T_IU, ( pres >> 3 ) );

               temp_factor = temp_factor * ((U_INT16)DET_TCOMP_STD_TEMP_IU - module_temperature) / CORRECT_SCALE;


               uncorrected_pres = pres + pres_factor + temp_factor;

               if ( (pres_factor + temp_factor) >= 0 )
               {
                    if ( pres > uncorrected_pres ) uncorrected_pres = 0xffff; /* overflow */
               }
               else
               {
                   if ( uncorrected_pres > pres  ) uncorrected_pres = 0; /* underflow */
               }

               pres_factor = tableS((INT32 *)frit->Setpt_Pres_Correct_Per_P_IU, ( uncorrected_pres >> 3 ) );

               pres_factor = pres_factor * ((U_INT16)DET_TCOMP_STD_PRES_IU - atm_pres) / CORRECT_SCALE
                               - ( (U_INT16)DET_TCOMP_STD_PRES_IU - atm_pres );

               temp_factor = tableS((INT32 *)frit->Setpt_Temp_Correct_Per_T_IU, ( uncorrected_pres >> 3 ) );

               temp_factor = temp_factor * ((U_INT16)DET_TCOMP_STD_TEMP_IU - module_temperature) / CORRECT_SCALE;


               uncorrected_pres = pres + pres_factor + temp_factor;

               if ( (pres_factor + temp_factor) >= 0 )
               {
                    if ( pres > uncorrected_pres ) uncorrected_pres = 0xffff; /* overflow */
               }
               else
               {
                   if ( uncorrected_pres > pres  ) uncorrected_pres = 0; /* underflow */
               }

          }
          else
          {
              uncorrected_pres = pres;
              temp_factor = 0;
              pres_factor = 0;
          }

          flow = tableU((U_INT32 *)frit->Pres_To_Flow, uncorrected_pres );
     }
     else
     {
          uncorrected_pres = pres;
          temp_factor = 0;
          pres_factor = 0;
          flow = 0;
     }

     frit->Pres_Actual = pres;
     frit->TCorr_Actual = temp_factor;
     frit->PCorr_Actual = pres_factor;
     frit->UPres_Actual = uncorrected_pres;

     return flow;

}

/***********************************************************************/
/* FUNCTION:                                                           */
/* ========                                                            */
/*                                                                     */
/* PURPOSE:                                                            */
/*                                                                     */
/* RETURNED VALUE:                                                     */
/*                                                                     */
/* GLOBALS USED:                                                       */
/*                                                                     */
/***********************************************************************/
/**begin_proto**/

U_INT16 VoltsToAtmPres( U_INT16 volts )

/**end_proto**/
{
    U_INT16  temp;

    temp = ((INT32)volts * (ATMP_SLOPE))  / (ATMP_SCALE) + (ATMP_OFFSET);

    if (temp < (MIN_ALLOWED_ATM_PRES))
    {
       temp = (MIN_ALLOWED_ATM_PRES);
    }
    else
    {
       if (temp > (MAX_ALLOWED_ATM_PRES))
       {
          temp = (MAX_ALLOWED_ATM_PRES);
       }
    }

    return temp;
}


/**begin_proto**/

#pragma SECTION UNDO

/**end_proto**/
